package loadsave;

import java.io.FileNotFoundException;
import java.io.PrintStream;

import loadsave.loadsaveobject.*;

public class OMLSaver implements Saver {
	
	private class OutputWriter {
		private PrintStream ps = System.out;
		private int tabLevel = 0;
		private String tabString = "";
		
		OutputWriter(PrintStream newOutStream) { ps = newOutStream; }
		
		void printlnWithTabs(String s) { ps.println(getTabString() + s); }
		
		private String getTabString() { return tabString; }
		
		void incrementTabs() { ++tabLevel; recalculateTabString(); }
		
		void decrementTabs() { --tabLevel; recalculateTabString(); }
		
		private void recalculateTabString() {
			StringBuilder tabs = new StringBuilder();
			for (int i = 0; i < tabLevel; ++i)
				tabs.append('\t');
			tabString = tabs.toString();
		}
	}
	
	OutputWriter out;
	
	public OMLSaver() {
		out = new OutputWriter(System.out);
	}
	
	public OMLSaver(PrintStream newOutStream) {
		out = new OutputWriter(newOutStream);
	}
	
	public OMLSaver(String filename) {
		try {
			out = new OutputWriter(new PrintStream(filename));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			out = new OutputWriter(System.out);
		}
	}
	
	private String getNameTypePrefix(LoadSaveObject l) {
		String name = l.getName(), type = l.getType();
		StringBuilder s = new StringBuilder();
		if (!name.equals(""))
			s.append(name + " ");
		s.append(':');
		if (!type.equals(""))
			s.append(" " + type + " ");
		s.append(": ");
		return s.toString();
	}
	
	@Override
	public void saveLoadSavePrimitive(LoadSavePrimitive l) {
		out.printlnWithTabs(getNameTypePrefix(l) + "\"" + l.getValue() + "\"");
	}

	@Override
	public void saveLoadSaveObjectComposite(LoadSaveObjectComposite l) {
		out.printlnWithTabs(getNameTypePrefix(l) + "{");
		out.incrementTabs();
		Iterator<LoadSaveObject> i = l.getIterator();
		for (i.init(); i.hasNext(); i.next()) {
			i.getCurrVal().save(this);
		}
		out.decrementTabs();
		out.printlnWithTabs("}");
	}

	@Override
	public void saveLoadSaveMapComposite(LoadSaveMapComposite l) {
		out.printlnWithTabs(getNameTypePrefix(l) + "[ <" + l.getKeyType() + ", " + l.getValType() + ">");
		out.incrementTabs();
		Iterator<LoadSaveObject> i = l.getIterator();
		for (i.init(); i.hasNext(); i.next()) {
			i.getCurrKey().save(this);
			out.incrementTabs();
			i.getCurrVal().save(this);
			out.decrementTabs();
		}
		out.decrementTabs();
		out.printlnWithTabs("]");
	}

	@Override
	public void saveLoadSaveCollectionComposite(LoadSaveCollectionComposite l) {
		out.printlnWithTabs(getNameTypePrefix(l) + "[ <" + l.getValType() + ">");
		out.incrementTabs();
		l.getSize().save(this);
		Iterator<LoadSaveObject> i = l.getIterator();
		for (i.init(); i.hasNext(); i.next()) {
			i.getCurrKey().save(this);
			out.incrementTabs();
			i.getCurrVal().save(this);
			out.decrementTabs();
		}
		out.decrementTabs();
		out.printlnWithTabs("]");
	}

	@Override
	public void saveLoadSaveIndex(LoadSaveIndex l) {
		StringBuilder result = new StringBuilder();
		result.append(getNameTypePrefix(l));
		for (int index : l.getIndices()) {
			result.append(index);
			result.append(", ");
		}
		out.printlnWithTabs(result.substring(0, result.length() - 2));
	}

	@Override
	public void save(LoadSaveable toSave) {
		//Woohoo LoD!!!
		toSave.getMemento().getState().save(this);
	}

}
